package com.aplink.generic.webservice;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.ref.WeakReference;
import java.util.ArrayList;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.json.JSONException;

import android.os.AsyncTask;

import com.aplink.generic.GenericFragment;
import com.aplink.generic.constant.WebServiceContant;
import com.aplink.generic.constant.type.ActionType;
import com.aplink.generic.constant.type.DialogStatus;
import com.aplink.generic.controller.GenericApplication;
import com.aplink.generic.interfaces.OnHttpTaskPostExcute;
import com.aplink.generic.util.LogUtil;

public class HttpTask extends AsyncTask<HttpURL, Void, ArrayList<DataResult>> {
    public static int CONNECTION_TIME_OUT = 10000;
    public static int SO_TIME_OUT = 10000;
    private WeakReference<GenericFragment> mFragment;
    private OnHttpTaskPostExcute mHttpTaskPostExcute;
    private int mTaskSize = 0;
    private final ActionType mTaskType;

    public HttpTask(final ActionType actionType) {
        this.mTaskType = actionType;
    }

    public HttpTask(final GenericFragment fragment, final ActionType taskType) {
        this.mFragment = new WeakReference<GenericFragment>(fragment);
        this.mTaskType = taskType;
    }

    @Override
    protected ArrayList<DataResult> doInBackground(final HttpURL... params) {
        final ArrayList<DataResult> results = new ArrayList<DataResult>();
        this.mTaskSize = params.length;
        for (final HttpURL url : params) {
            results.add(excuteRequest(url));
        }
        return results;
    }

    private DataResult excuteRequest(final HttpURL genericUrl) {
        final StringBuilder stringBuilder = new StringBuilder();
        try {
            DataResult dataResult = new DataResult();
            final HttpParams httpParameters = new BasicHttpParams();
            HttpConnectionParams.setConnectionTimeout(httpParameters,
                    HttpTask.CONNECTION_TIME_OUT);
            HttpConnectionParams.setSoTimeout(httpParameters,
                    HttpTask.SO_TIME_OUT);
            final HttpClient httpClient = new DefaultHttpClient(httpParameters);
            HttpUriRequest request = null;
            if (genericUrl.getMethod() == WebServiceContant.POST) {
                final HttpPost httppost = new HttpPost(
                        genericUrl.getWebserviceURL());
                httppost.setEntity(genericUrl.getHttpEntity());
                request = httppost;
            } else {
                request = new HttpGet(genericUrl.getWebserviceURL());
            }
            final int tryTime = GenericApplication.getInstance()
                    .getMasterConfig().getTryTime();
            final HttpResponse response = requestToServer(httpClient, request,
                    tryTime, genericUrl);
            final StatusLine statusLine = response.getStatusLine();
            final HttpResponseStatus statusCode = HttpResponseStatus
                    .get(statusLine.getStatusCode());
            final HttpEntity entity = response.getEntity();
            final InputStream content = entity.getContent();
            final BufferedReader reader = new BufferedReader(
                    new InputStreamReader(content));
            String line;
            while ((line = reader.readLine()) != null) {
                stringBuilder.append(line);
            }
            String result = stringBuilder.toString().replace(
                    "<?xml version=\"1.0\" encoding=\"utf-8\"?>", "");
            result = result.replace("<string xmlns=\"http://aplink.com.sg/\">",
                    "");
            result = result.replace("<string xmlns=\"http://tempuri.org/\">",
                    "");
            result = result.replace("</string>", "");
            LogUtil.info(LogUtil.TAG_WEBSERVICE, result, "Webservice response",
                    getClass());
            if (statusCode.equals(HttpResponseStatus.SUCCESS)) {
                if ((this.mTaskType == ActionType.INIT_DATA)
                        || (this.mTaskType == ActionType.DOWNLOAD)
                        || (this.mTaskType == ActionType.UPLOAD)
                        || (this.mTaskType == ActionType.AUTO_SYNC)) {
                    dataResult = WebServiceParser.getInstance().parse(result,
                            genericUrl.initTableName(),
                            genericUrl.getContentData());
                } else {
                    dataResult = WebServiceParser.getInstance().parse(result,
                            genericUrl.getContentData(),
                            this.mFragment.get().getBindingObject());
                }
                reader.close();
            }
            dataResult.setStatusCode(statusCode);
            dataResult.setObjPropCol(genericUrl.getContentData());
            dataResult.setGenericObject(genericUrl.getGenericObject());
            return dataResult;
        } catch (final IOException e) {
            final String message = String.format(
                    "Can't open connection to: %s. The connection was aborted",
                    genericUrl.toString());
            LogUtil.error(LogUtil.TAG_WEBSERVICE, message,
                    "excute Get Request", getClass());

        } catch (final JSONException e) {
            final String message = String.format(
                    "Can not creates a new JSONArray with values from %s ",
                    stringBuilder.toString());
            LogUtil.error(LogUtil.TAG_WEBSERVICE, message,
                    "excute Get Request", getClass());
        }
        return DataResult.obtain(null, HttpResponseStatus.UNKNOW_ERROR);
    }

    public OnHttpTaskPostExcute getHttpTaskPostExcute() {
        return this.mHttpTaskPostExcute;
    }

    @Override
    protected void onPostExecute(final ArrayList<DataResult> result) {
        super.onPostExecute(result);
        if (this.mHttpTaskPostExcute == null) {
            if (this.mFragment.get() != null) {
                if (result.isEmpty() && (this.mTaskSize == 0)) {
                    if (this.mTaskType.equals(ActionType.UPLOAD)) {
                        if (this.mFragment.get().hasRegisterProgressDialog(
                                ActionType.UPLOAD)) {
                            this.mFragment.get()
                                    .getProgressDialog(ActionType.UPLOAD)
                                    .dismiss();
                        }
                        this.mFragment.get().getAlertDialog()
                                .show(this.mTaskType, DialogStatus.SUCCESSFUL);
                    }
                } else {
                    this.mFragment.get().getGenericHandler()
                            .obtainMessage(this.mTaskType.getCode(), result)
                            .sendToTarget();
                }
            }
        } else {
            this.mHttpTaskPostExcute.onPostExecute(result);
        }
    }

    private HttpResponse requestToServer(final HttpClient httpClient,
            final HttpUriRequest request, final int tryTime,
            final HttpURL genericUrl) throws IOException {
        int i = 1;
        boolean hasError = true;
        IOException e = null;
        while ((i < tryTime) && hasError) {
            try {
                final String message = String.format(i
                        + ": Connect to server: %s", genericUrl.toString());
                LogUtil.info(LogUtil.TAG_WEBSERVICE, message,
                        "requestToServer", getClass());
                final HttpResponse response = httpClient.execute(request);
                hasError = false;
                return response;
            } catch (final IOException ex) {
                hasError = true;
                e = ex;
            }
            i++;
        }
        if (hasError) {
            throw e;
        }
        return null;
    }

    public void setHttpTaskPostExcute(
            final OnHttpTaskPostExcute httpTaskPostExcute) {
        this.mHttpTaskPostExcute = httpTaskPostExcute;
    }
}
